package com.wangshuqi.jdbc.transaction;

import com.wangshuqi.jdbc.util.JDBCUtil;
import org.junit.Test;

import java.sql.Connection;
import java.sql.SQLException;

/**
 * 数据库事务
 *
 * @author codewsq
 * @date 2021/8/26 0026 10:56
 */
public class JDBCTransactionTest {


    /*
     * 没有事务，普通操作转账会出现的问题
     * */
    @Test
    public void testNoTransaction() {
        /*
         *  操作数据，AA给BB转账100，
         *   运行正常：AA余额减100，BB余额加100
         *   抛出异常：AA余额少了100，但是BB的余额并没有加上100，数据丢失，一致性出现问题
         * */
        String sql1 = "update user_table set balance = balance-100 where user = ?";
        JDBCUtil.saveOrUpdateOrDelete(sql1, "AA");
        int i = 10 / 0; // 模拟异常
        String sql2 = "update user_table set balance = balance+100 where user = ?";
        JDBCUtil.saveOrUpdateOrDelete(sql2, "BB");
    }


    /*
     * 通过事务解决转账问题
     *   运行正常：AA余额减100，BB余额加100
     *   抛出异常：数据回滚，AA和BB的余额都保持不变
     * */
    @Test
    public void testTransaction() {
        Connection connection = null;
        try {
            // 1.获取连接
            connection = JDBCTransactionUtil.getConnection();
            // 2. 关闭自动提交
            connection.setAutoCommit(false);
            // 3. 操作数据，AA给BB转账100， AA余额减100，BB余额加100
            String sql1 = "update user_table set balance = balance-100 where user = ?";
            JDBCTransactionUtil.saveOrUpdateOrDelete(connection, sql1, "AA");

            int i = 10 / 0; // 模拟异常

            String sql2 = "update user_table set balance = balance+100 where user = ?";
            JDBCTransactionUtil.saveOrUpdateOrDelete(connection, sql2, "BB");
            // 4-1.提交事务
            connection.commit();
        } catch (Exception e) {
            e.printStackTrace();
            try {
                // 4-2.出现异常，事务回滚，保证数据一致
                connection.rollback();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        } finally {
            // 5.关闭连接
            JDBCTransactionUtil.closeConnection(connection);
        }
    }


    /*
     * 附加：数据库隔离级别设置
     * */
    @Test
    public void test() throws Exception {
        /*
        * Connection连接的事务隔离级别：
            int TRANSACTION_READ_UNCOMMITTED = 1; // 读未提交，什么问题都未解决，但是性能最佳
            int TRANSACTION_READ_COMMITTED   = 2; // 读已提交，解决脏读问题，但是不可重复读和脏读问题都未解决
            int TRANSACTION_REPEATABLE_READ  = 4; // 可重复读，可结局不可重复读的问题
            int TRANSACTION_SERIALIZABLE     = 8; // 串行化，问题都已解决，但是性能最差
        *
        * */
        Connection connection = JDBCTransactionUtil.getConnection();
        // 获取当前事务的隔离级别 mysql默认隔离级是 可重复读 REPEATABLE READ
        int transactionIsolation = connection.getTransactionIsolation();
        System.out.println(transactionIsolation);
        // 设置事务隔离级别为：读已提交
        connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);

    }
}
